using System;
using SMS.SMPPClient.PDU;
using SMS.SMPPClient.Util;

namespace SMS.SMPPClient.PDU.Outgoing
{
    /// <summary>
    /// Provides some common attributes for data_sm, submit_sm, and submit_multi.
    /// </summary>
    public abstract class MessageLCD3 : MessageLCD4
    {
        protected string _ServiceType;
        protected byte _ESMClass;
        protected DataCodingType _DataCoding;

        /// <summary>
        /// Enumerates the source address subunit types.
        /// </summary>
        public enum AddressSubunitType : byte
        {
            Unknown = 0x00,
            MSDisplay = 0x01,
            MobileEquipment = 0x02,
            SmartCard1 = 0x03,
            ExternalUnit1 = 0x04
        }

        /// <summary>
        /// Enumerates the display time type.
        /// </summary>
        public enum DisplayTimeType : byte
        {
            Temporary = 0x00,
            Default = 0x01,
            Invoke = 0x02
        }

        /// <summary>
        /// Enumerates the MS Display type.
        /// </summary>
        public enum MSValidityType : byte
        {
            StoreIndefinitely = 0x00,
            PowerDown = 0x01,
            SIDBased = 0x02,
            DisplayOnly = 0x03
        }

        #region optional params
        /// <summary>
        /// The application port number associated with the source address of the message.
        /// This parameter should be present for WAP applications.
        /// </summary>
        public UInt16 SourcePort
        {
            get
            {
                return UnsignedNumConverter.SwapByteOrdering(
                    BitConverter.ToUInt16(tlvTable.GetOptionalParamBytes(
                    (UInt16)PDU.OptionalParamCodes.source_port), 0));
            }
            set
            {
                if (value < UInt16.MaxValue)
                {
                    tlvTable.SetOptionalParamBytes(
                        (UInt16)PDU.OptionalParamCodes.source_port,
                        BitConverter.GetBytes(
                            UnsignedNumConverter.SwapByteOrdering(value)));
                }
                else
                {
                    throw new ArgumentException(
                        "source_port value too large.");
                }
            }
        }

        /// <summary>
        /// The subcomponent in the destination device which created the user data.
        /// </summary>
        public AddressSubunitType SourceAddrSubunit
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.source_addr_subunit, new Byte[] {
					( byte )value
				});
            }
        }

        /// <summary>
        /// The application port number associated with the destination address of the
        /// message.  This parameter should be present for WAP applications.
        /// </summary>
        public UInt16 DestinationPort
        {
            get
            {
                return UnsignedNumConverter.SwapByteOrdering(
                    BitConverter.ToUInt16(tlvTable.GetOptionalParamBytes(
                    (UInt16)PDU.OptionalParamCodes.destination_port), 0));
            }
            set
            {
                if (value < UInt16.MaxValue)
                {
                    tlvTable.SetOptionalParamBytes(
                        (UInt16)PDU.OptionalParamCodes.destination_port,
                        BitConverter.GetBytes(
                            UnsignedNumConverter.SwapByteOrdering(value)));
                }
                else
                {
                    throw new ArgumentException(
                        "destination_port value too large.");
                }
            }
        }

        /// <summary>
        /// The reference number for a particular concatenated short message.  Both
        /// SarTotalSegments and SarSegmentSeqnum need to be set in conjunction with this
        /// property.  In addition, this must be the same for each segment.
        /// </summary>
        protected UInt16 SarMsgRefNumber
        {
            get
            {
                return UnsignedNumConverter.SwapByteOrdering(
                    BitConverter.ToUInt16(tlvTable.GetOptionalParamBytes(
                    (UInt16)PDU.OptionalParamCodes.sar_msg_ref_num), 0));
            }
            set
            {
                if (value < UInt16.MaxValue)
                {
                    tlvTable.SetOptionalParamBytes(
                        (UInt16)PDU.OptionalParamCodes.sar_msg_ref_num,
                        BitConverter.GetBytes(
                            UnsignedNumConverter.SwapByteOrdering(value)));
                }
                else
                {
                    throw new ArgumentException(
                        "sar_msg_ref_number value too large.");
                }
            }
        }

        /// <summary>
        /// Indicates the total number of short messages within the concatenated short
        /// message.  Both SarMsgRefNumber and SarSegmentSeqNum need to be set in
        /// conjunction with this property.  In addition, this must be the same for each
        /// segment.
        /// </summary>
        protected byte SarTotalSegments
        {
            set
            {
                if (value >= 1 && value <= 255)
                {
                    tlvTable.SetOptionalParamBytes(
                        (ushort)PDU.OptionalParamCodes.sar_total_segments, new Byte[] {
						( byte )value
					});
                }
                else
                {
                    throw new ArgumentException(
                        "sar_total_segments must be >= 1 and <= 255 ");
                }
            }
        }

        /// <summary>
        /// The sequence number of a particular short message within the concatenated
        /// short message.  Both SarMsgRefNumber and SarTotalSegments need to be set in
        /// conjunction with this property.
        /// </summary>
        protected byte SarSegmentSeqnum
        {
            set
            {
                if (value >= 1 && value <= 255)
                {
                    tlvTable.SetOptionalParamBytes(
                        (ushort)PDU.OptionalParamCodes.sar_segment_seqnum, new Byte[] {
						( byte )value
					});
                }
                else
                {
                    throw new ArgumentException(
                        "sar_segment_seqnum must be >= 1 and <= 255 ");
                }
            }
        }

        /// <summary>
        /// Defines the type of payload.
        /// </summary>
        public PayloadTypeType PayloadType
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.payload_type, new Byte[] {
					( byte )value
				});
            }
        }

        /// <summary>
        /// Contains the extended short message user data.  Up to 64K octets can be
        /// transmitted.  The limit for this is network/SMSC dependent.
        /// </summary>
        public object MessagePayload
        {
            set
            {
                byte[] encodedValue;

                if (value is string)
                    encodedValue = System.Text.Encoding.ASCII.GetBytes(
                                         (string)value);
                else if (value is byte[])
                    encodedValue = (byte[])value;
                else
                    throw new ArgumentException(
                        "Message Payload must be a string or byte array.");

                if (encodedValue.Length < 64000)
                    tlvTable.SetOptionalParamBytes(
                        (ushort)PDU.OptionalParamCodes.message_payload,
                        encodedValue);
                else
                    throw new ArgumentException(
                        "Message Payload must be 64K characters or less in size.");
            }
        }

        /// <summary>
        /// The privacy level of the message.
        /// </summary>
        public PrivacyType PrivacyIndicator
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.privacy_indicator, new Byte[] {
					( byte )value
				});
            }
        }

        /// <summary>
        /// ESME assigned message reference number.
        /// </summary>
        public UInt16 UserMessageReference
        {
            get
            {
                return UnsignedNumConverter.SwapByteOrdering(
                    BitConverter.ToUInt16(tlvTable.GetOptionalParamBytes(
                    (UInt16)PDU.OptionalParamCodes.user_message_reference), 0));
            }
            set
            {
                if (value < UInt16.MaxValue)
                {
                    tlvTable.SetOptionalParamBytes(
                        (UInt16)PDU.OptionalParamCodes.user_message_reference,
                        BitConverter.GetBytes(
                            UnsignedNumConverter.SwapByteOrdering(value)));
                }
                else
                {
                    throw new ArgumentException(
                        "user_message_reference too large.");
                }
            }
        }

        /// <summary>
        /// Allows an indication to be provided to an MS that there are
        /// messages waiting for the subscriber on systems on the PLMN. The indication
        /// can be an icon on the MS screen or other MMI indication.
        /// See section 5.3.2.13 for details on how to set this.
        /// </summary>
        public byte MSMsgWaitFacilities
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.ms_msg_wait_facilities, new Byte[] {
					value
				});
            }
        }

        /// <summary>
        /// Provides a MS with validity information associated with the received
        /// short message.
        /// </summary>
        public MSValidityType MSValidity
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.ms_validity, new Byte[] {
					( byte )value
				});
            }
        }

        /// <summary>
        /// Provides a TDMA MS station with alert tone information associated with the
        /// received short message.
        /// </summary>
        public UInt16 SMSSignal
        {
            get
            {
                return UnsignedNumConverter.SwapByteOrdering(
                    BitConverter.ToUInt16(tlvTable.GetOptionalParamBytes(
                    (UInt16)PDU.OptionalParamCodes.sms_signal), 0));
            }
            set
            {
                if (value < UInt16.MaxValue)
                {
                    tlvTable.SetOptionalParamBytes(
                        (UInt16)PDU.OptionalParamCodes.sms_signal,
                        BitConverter.GetBytes(
                            UnsignedNumConverter.SwapByteOrdering(value)));
                }
                else
                {
                    throw new ArgumentException(
                        "sms_signal value too large.");
                }
            }
        }

        /// <summary>
        /// The subcomponent in the destination device for which the user data is intended.
        /// </summary>
        public AddressSubunitType DestAddrSubunit
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.dest_addr_subunit, new Byte[] {
					( byte )value
				});
            }
        }

        /// <summary>
        /// Tells a mobile station to alert the user when the short message arrives at the MS.
        ///
        /// Note: there is no value part associated with this parameter.
        /// Any value you pass in will be discarded.
        /// </summary>
        public byte AlertOnMsgDelivery
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.alert_on_message_delivery, new Byte[0]);
            }
        }

        /// <summary>
        /// The language of the short message.
        /// </summary>
        public LanguageType LanguageIndicator
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.language_indicator,
                    new Byte[] {
					( byte )value
				});
            }
        }

        /// <summary>
        /// Associates a display time with the short message on the MS.
        /// </summary>
        public DisplayTimeType DisplayTime
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.display_time, new Byte[] {
					( byte )value
				});
            }
        }

        /// <summary>
        /// Associates a call back number with the message.  See section 5.3.2.36 of the
        /// SMPP spec for details.  This must be between 4 and 19 characters in length.
        /// </summary>
        public string CallbackNum
        {

            set
            {
                if (value.Length >= 4 &&
                        value.Length <= 19)
                {
                    tlvTable.SetOptionalParamString(
                        (ushort)PDU.OptionalParamCodes.callback_num, value);
                }
                else
                {
                    throw new ArgumentException(
                        "callback_num size must be between 4 and 19 " +
                        "characters.");
                }
            }
        }

        /// <summary>
        /// Controls the presentation indication and screening of the CallBackNumber at the
        /// mobile station.  You must also use the callback_num parameter with this.
        /// See section 5.3.2.37 of the SMPP spec for details in how to set this.
        /// </summary>
        public byte CallbackNumPresInd
        {
            set
            {
                tlvTable.SetOptionalParamBytes(
                    (ushort)PDU.OptionalParamCodes.callback_num_pres_ind,
                    new Byte[] {
					value
				});
            }
        }

        /// <summary>
        /// Alphanumeric display tag for call back number.  This must be less than or
        /// equal to 65 characters in length.
        /// </summary>
        public string CallbackNumAtag
        {
            set
            {
                if (value.Length <= 65)
                {
                    tlvTable.SetOptionalParamString(
                        (ushort)PDU.OptionalParamCodes.callback_num_atag, value);
                }
                else
                {
                    throw new ArgumentException(
                        "Callback number atag must be <= 65.");
                }
            }
        }

        /// <summary>
        /// Specifies a subaddress associated with the originator of the message.
        /// See section 5.3.2.15 of the SMPP spec for details on
        /// setting this parameter.
        /// </summary>
        public string SourceSubaddress
        {
            set
            {
                if (value.Length >= 2 && value.Length <= 23)
                {
                    tlvTable.SetOptionalParamString(
                        (ushort)PDU.OptionalParamCodes.source_subaddress, value);
                }
            }
        }

        /// <summary>
        /// Specifies a subaddress associated with the receiver of the message.
        /// See section 5.3.2.15 of the SMPP spec for details on
        /// setting this parameter.
        /// </summary>
        public string DestSubaddress
        {
            set
            {
                if (value.Length >= 2 && value.Length <= 23)
                {
                    tlvTable.SetOptionalParamString(
                        (ushort)PDU.OptionalParamCodes.dest_subaddress, value);
                }
            }
        }
        #endregion optional params

        /// <summary>
        /// Groups construction tasks for subclasses.
        /// </summary>
        /// <param name="serviceType">Used to indicate the SMS Application service associated
        /// with the message.</param>
        /// <param name="esmClass">Indicates Message Mode and Message Type.  See the SMSC
        /// version 3.4 specification for details on setting this.  For most uses, you can
        /// set this to 0 (default SMSC actions).</param>
        /// <param name="registeredDelivery">The registered delivery type.</param>
        /// <param name="sourceAddrTON">The type of number of the source address.</param>
        /// <param name="sourceAddrNPI">The number plan indicator of the source
        /// address.</param>
        /// <param name="sourceAddress">The source address.</param>
        /// <param name="dataCoding">Defines the encoding scheme of the short message user
        /// data.</param>
        protected MessageLCD3(string serviceType, byte esmClass,
                            RegisteredDeliveryType registeredDelivery,
                            TONType sourceAddrTON, NPIType sourceAddrNPI,
                            string sourceAddress, DataCodingType dataCoding)
            :
                base(registeredDelivery, sourceAddrTON, sourceAddrNPI, sourceAddress)
        {

            if (serviceType != null)
            {
                if (serviceType.Length <= SERVICE_TYPE_LENGTH)
                    _ServiceType = serviceType;
                else
                    throw new ArgumentOutOfRangeException(
                        "Service Type must be " + SERVICE_TYPE_LENGTH +
                        " 5 characters or less.");
            }
            else
                _ServiceType = "";

            _ESMClass = esmClass;
            _DataCoding = dataCoding;
        }
    }
}
